package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author ikun
 * @since 2024-08-22
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    private final ILearningLessonService lessonService;
    private final CourseClient courseClient;

    @Transactional
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        //登录获取进度
        Long user = UserContext.getUser();
        // 2.查询课表
        LearningLesson lesson = lessonService.queryByUserAndCourseId(user, courseId);
        // 3.查询学习记录
        List<LearningRecord> query = lambdaQuery()
                .eq(LearningRecord::getLessonId, lesson.getId())
                .list();
        // 4.封装数据
        LearningLessonDTO learningLessonDTO = new LearningLessonDTO();
        learningLessonDTO.setId(lesson.getId());
        learningLessonDTO.setLatestSectionId(lesson.getLatestSectionId());
        learningLessonDTO.setRecords(BeanUtils.copyList(query, LearningRecordDTO.class));
        return learningLessonDTO;
    }

    @Override
    @Transactional
    public void addLearningRecord(LearningRecordFormDTO recordDTO) {

        //获取登录用户
        Long userId = UserContext.getUser();
        //处理学习记录
        boolean finished = false;
        if (recordDTO.getSectionType() == SectionType.VIDEO) {
            //处理视频
            finished = handleVideoRecord(userId, recordDTO);
        } else {
            //处理考试
            finished = handleExamRecord(userId, recordDTO);
        }
        //处理课表数据
        handleLearningLessonsChanges(recordDTO, finished);
    }

    /**
     * 处理学习课程的进度变更
     * 当用户完成课程中的一个新小节时，更新课表中的学习状态
     *
     * @param recordDTO 学习记录表单数据传输对象，包含更新所需的数据
     * @param finished  布尔值，表示用户是否完成了新的小节
     */
    private void handleLearningLessonsChanges(LearningRecordFormDTO recordDTO, boolean finished) {
        // 根据记录中的课程ID，查询课表信息，以获取当前课程的学习状态
        LearningLesson lesson = lessonService.getById(recordDTO.getLessonId());
        if (lesson == null) {
            // 如果课表不存在，抛出异常，提示无法更新数据
            throw new BizIllegalException("课表不存在,无法更新数据");
        }

        // 标记课程是否全部学完，默认为false
        boolean allLearned = false;
        if (finished) {
            // 如果有新完成的小节，则需要查询课程的详细数据
            CourseFullInfoDTO course = courseClient.getCourseInfoById(lesson.getCourseId(), false, false);
            if (course == null) {
                // 如果课程不存在，抛出异常，提示无法更新数据
                throw new BizIllegalException("课程不存在,无法更新数据");
            }
            // 比较课程是否全部学完：已学习小节 >= 课程总小节
            allLearned = course.getSectionNum() <= lesson.getLearnedSections();

        }
        // 更新课表信息
        lessonService.lambdaUpdate()
                // 如果当前课表的小节学习数量为0，则更新状态为学习中
                .set(lesson.getLearnedSections() == 0, LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                // 如果课程全部学完，则更新状态为已完成
                .set(allLearned, LearningLesson::getStatus, LessonStatus.FINISHED.getValue())
                // 如果小节未完成，则更新最新的小节ID
                .set(!finished, LearningLesson::getLatestSectionId, recordDTO.getSectionId())
                // 如果小节未完成，则更新最新的学习时间
                .set(!finished, LearningLesson::getLatestLearnTime, recordDTO.getCommitTime())
                // 如果小节完成，则执行SQL，累加已学习的小节数量
                .setSql(finished, "learned_sections = learned_sections + 1")
                // 根据ID匹配课表记录，执行更新操作
                .eq(LearningLesson::getId, lesson.getId())
                .update();
    }


    private boolean handleExamRecord(Long userId, LearningRecordFormDTO recordDTO) {
        LearningRecord learningRecord = BeanUtils.copyBean(recordDTO, LearningRecord.class);
        //填充数据
        learningRecord.setUserId(userId);
        learningRecord.setFinished(true);
        learningRecord.setFinishTime(recordDTO.getCommitTime());
        boolean save = save(learningRecord);
        if (!save) {
            throw new DbException("新增学习记录失败");
        }
        return true;
    }

    private boolean handleVideoRecord(Long userId, LearningRecordFormDTO recordDTO) {
        //1.查询旧的学习记录
        LearningRecord old = queryOldRecord(recordDTO.getLessonId(), recordDTO.getSectionId());

        //2.判断学习记录是否存在
        if (old == null) {
            //不存在，新增学习记录
            LearningRecord record = BeanUtils.copyBean(recordDTO, LearningRecord.class);
            record.setUserId(userId);
            boolean save = save(record);
            if (!save) {
                throw new DbException("新增学习记录失败");
            }
            return false;
        }
        // 4.存在，则更新
        // 4.1.判断是否是第一次完成
        boolean finished = !old.getFinished() && recordDTO.getMoment() * 2 >= recordDTO.getDuration();
        //更新学习计划
        boolean update = lambdaUpdate()
                .set(LearningRecord::getMoment, recordDTO.getMoment())
                .set(finished, LearningRecord::getFinished, true)
                .set(finished, LearningRecord::getFinishTime, recordDTO.getCommitTime())
                .eq(LearningRecord::getId, old.getId())
                .update();
        if (!update) {
            throw new DbException("更新学习记录失败");
        }
        return finished;
    }

    /**
     * 查询旧的学习记录
     * 此方法用于根据课程ID和章节ID查询之前的学习记录它通过lambdaQuery方式构建查询条件，
     * 包括课程ID和章节ID，以确保查询结果的精确性该方法返回查询到的学习记录对象，
     * 如果没有找到匹配的记录，则返回null
     *
     * @param lessonId  课程ID，用于指定查询的课程
     * @param sectionId 章节ID，用于指定查询的课程中的特定章节
     * @return 返回查询到的学习记录对象，如果没有找到匹配的记录，则返回null
     */
    private LearningRecord queryOldRecord(Long lessonId, Long sectionId) {
        return lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
    }


}
